package zh.guocw.hc;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * An implementation of the Reactor pattern
 * 
 */
public class Reactor extends Thread{
    // bind it to this Reactor
    Selector selector ;
    
    //Should run flag. False if IOException or invoke stopReactor method
    protected volatile boolean _shouldRun = true;
    
    /**
     * @throws IOException - If an I/O error occurs
     * */
    public Reactor() throws IOException {
    	selector = Selector.open();
	}
    
    /**
     * 注意调用SelectionKey的cancel方法，将使其对应的SelectableChannel从Selector中移除。
     * */
	@Override
	public void run() {
		//There is no Runnable target
		//super.run();
		
		// Get the number of keys, possibly zero, whose ready-operation sets were updated
		try {
            while (_shouldRun) {
                // Wait for an event
            	int keyNum = selector.select();
            	System.out.println("selector.keys().size()="+selector.keys().size());
            	
            	if(keyNum > 0){
                    System.out.println("==== select() ====");
            		// Get list of selection keys with pending events
                    Iterator<SelectionKey> it = selector.selectedKeys().iterator();
                    
                    // Process each key
                    while (it.hasNext()) {
                        // Get the selection key
                        SelectionKey selKey = it.next();
                        // Remove it from the list to indicate that it is being processed
                        it.remove();
/*
                        OP_READ    1<<0 = 1
						OP_WRITE   1<<2 = 4
						OP_CONNECT 1<<2 = 8
						OP_ACCEPT  1<<2 = 16
*/
                        
                        System.out.println("interestOps="+selKey.interestOps());
                     //   selKey.cancel();
                        if(selKey.isWritable()){
                        	SocketChannel channel = (SocketChannel) selKey.channel();
                			StringBuffer buffer = new StringBuffer();
                			buffer.append("GET /"
                					+ " HTTP/1.1\r\n");
                			buffer.append("Host: "+channel.socket().getInetAddress().getHostAddress()+"\r\n");
                			buffer.append("\r\n");
                			System.out.println(buffer);
                        	channel.write(ByteBuffer.wrap(buffer.toString().getBytes()));
                            //selKey.interestOps(0);
                        	channel.register(this.selector, SelectionKey.OP_READ, selKey.attachment());
                        }
                        if(selKey.isReadable()){
                        	SocketChannel channel = (SocketChannel) selKey.channel();
                        	ByteBuffer dsts = ByteBuffer.allocate(80*1024);
                        	channel.read(dsts);
                        	System.out.println(new String(dsts.array(),0,200));
                        	channel.register(this.selector, SelectionKey.OP_WRITE, selKey.attachment());
                        }
                        if(selKey.isConnectable()){
                        	SocketChannel channel = (SocketChannel) selKey.channel();
                        	channel.finishConnect();
                        	if(channel.isConnected()){
                        		channel.register(this.selector, SelectionKey.OP_WRITE, selKey.attachment());
                        	}else{
                        		System.out.println(" not connected ="+channel.socket().getInetAddress());
                        	}
                        }

                    }
                    sleep(2000);
            	}else{
            		//
            		sleep(1000);
            	}
            }
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		// invoke stopReactor to close resources ralated.
		stopReactor();
		
	}
    
    /**
     * Stops the Reactor activity, including the Reactor thread and the Worker
     * Threads in the Thread Pool.
     */
    public void stopReactor(){
        _shouldRun = false;
       // _pool.stopPool();
    }

	public void add(NioSession session) throws ClosedChannelException {
		session.getClientChannel().register(this.selector, SelectionKey.OP_CONNECT, session);
	}
    
//	public void wakeup(){
//		this.selector.wakeup();
//	}
}
